<html> 
<head> 
    <script src="../../OLLoader.js"></script>
    <script type="text/javascript">

    var xml = new OpenLayers.Format.XML();
    function readXML(id) {
        return xml.read(document.getElementById(id).firstChild.nodeValue);
    }

    var sld =
        '<StyledLayerDescriptor version="1.0.0" ' +
            'xmlns="http://www.opengis.net/sld" ' +
            'xmlns:gml="http://www.opengis.net/gml" ' +
            'xmlns:ogc="http://www.opengis.net/ogc" ' +
            'xmlns:xlink="http://www.w3.org/1999/xlink" ' +
            'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
            'xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd">' +
            '<NamedLayer>' +
                '<Name>AAA161</Name>' +
                '<UserStyle>' +
                    '<FeatureTypeStyle>' +
                        '<Rule>' +
                            '<Name>stortsteen</Name>' +
                            '<ogc:Filter>' +
                                '<ogc:PropertyIsEqualTo>' +
                                    '<ogc:PropertyName>CTE</ogc:PropertyName>' +
                                    '<ogc:Literal>V0305</ogc:Literal>' +
                                '</ogc:PropertyIsEqualTo>' +
                            '</ogc:Filter>' +
                            '<MaxScaleDenominator>50000</MaxScaleDenominator>' +
                            '<PolygonSymbolizer>' +
                                '<Fill>' +
                                    '<CssParameter name="fill">#ffffff</CssParameter>' +
                                '</Fill>' +
                                '<Stroke>' +
                                    '<CssParameter name="stroke">#000000</CssParameter>' +
                                '</Stroke>' +
                            '</PolygonSymbolizer>' +
                            '<TextSymbolizer>' +
                                '<Label>' +
                                    'A <ogc:PropertyName>FOO</ogc:PropertyName> label' +
                                '</Label>' +
                                '<Font>' +
                                    '<CssParameter name="font-family">Arial</CssParameter>' +
                                    '<CssParameter name="font-size">14</CssParameter>' +
                                    '<CssParameter name="font-weight">bold</CssParameter>' +
                                    '<CssParameter name="font-style">normal</CssParameter>' +
                                '</Font>' +
                                '<LabelPlacement>' +
                                    '<PointPlacement>' +
                                        '<AnchorPoint>' +
                                            '<AnchorPointX>0.5</AnchorPointX>' +
                                            '<AnchorPointY>0.5</AnchorPointY>' +
                                        '</AnchorPoint>' +
                                        '<Displacement>' +
                                            '<DisplacementX>5</DisplacementX>' +
                                            '<DisplacementY>5</DisplacementY>' +
                                        '</Displacement>' +
                                        '<Rotation>45</Rotation>' +
                                    '</PointPlacement>' +
                                '</LabelPlacement>' +
                                '<Halo>' +
                                    '<Radius>3</Radius>' +
                                    '<Fill>' +
                                        '<CssParameter name="fill">#ffffff</CssParameter>' +
                                    '</Fill>' +
                                '</Halo>' +
                                '<Fill>' +
                                    '<CssParameter name="fill">#000000</CssParameter>' +
                                '</Fill>' +
                            '</TextSymbolizer>' +
                        '</Rule>' +
                        '<Rule>' +
                            '<Name>betonbekleding</Name>' +
                            '<ogc:Filter>' +
                                '<ogc:PropertyIsLessThan>' +
                                    '<ogc:PropertyName>CTE</ogc:PropertyName>' +
                                    '<ogc:Literal>1000</ogc:Literal>' +
                                '</ogc:PropertyIsLessThan>' +
                            '</ogc:Filter>' +
                            '<MaxScaleDenominator>50000</MaxScaleDenominator>' +
                            '<PolygonSymbolizer>' +
                                '<Fill>' +
                                    '<CssParameter name="fill">#ffff00</CssParameter>' +
                                '</Fill>' +
                                '<Stroke>' +
                                    '<CssParameter name="stroke">#0000ff</CssParameter>' +
                                '</Stroke>' +
                            '</PolygonSymbolizer>' +
                        '</Rule>' +
                    '</FeatureTypeStyle>' +
                '</UserStyle>' +
            '</NamedLayer>' +
            '<NamedLayer>' +
                '<Name>Second Layer</Name>' +
                '<UserStyle>' +
                    '<FeatureTypeStyle>' +
                        '<Rule>' +
                            '<Name>first rule second layer</Name>' +
                            '<ogc:Filter>' +
                                '<ogc:Or>' +
                                    '<ogc:PropertyIsBetween>' +
                                        '<ogc:PropertyName>number</ogc:PropertyName>' +
                                        '<ogc:LowerBoundary>' +
                                            '<ogc:Literal>1064866676</ogc:Literal>' +
                                        '</ogc:LowerBoundary>' +
                                        '<ogc:UpperBoundary>' +
                                            '<ogc:Literal>1065512599</ogc:Literal>' +
                                        '</ogc:UpperBoundary>' +
                                    '</ogc:PropertyIsBetween>' +
                                    '<ogc:PropertyIsLike wildCard="*" singleChar="." escape="!">' +
                                        '<ogc:PropertyName>cat</ogc:PropertyName>' +
                                        '<ogc:Literal>*dog.food!*good</ogc:Literal>' +
                                    '</ogc:PropertyIsLike>' +
                                    '<ogc:Not>' +
                                        '<ogc:PropertyIsLessThanOrEqualTo>' +
                                            '<ogc:PropertyName>FOO</ogc:PropertyName>' +
                                            '<ogc:Literal>5000</ogc:Literal>' +
                                        '</ogc:PropertyIsLessThanOrEqualTo>' +
                                    '</ogc:Not>' +
                                '</ogc:Or>' +
                            '</ogc:Filter>' +
                            '<MaxScaleDenominator>10000</MaxScaleDenominator>' +
                            '<PointSymbolizer>' +
                                '<Graphic>' +
                                    '<Mark>' +
                                        '<WellKnownName>star</WellKnownName>' +
                                        '<Fill>' +
                                            '<CssParameter name="fill">lime</CssParameter>' +
                                        '</Fill>' +
                                        '<Stroke>' +
                                            '<CssParameter name="stroke">olive</CssParameter>' +
                                            '<CssParameter name="stroke-width">2</CssParameter>' +
                                        '</Stroke>' +
                                    '</Mark>' +
                                    '<Size><ogc:PropertyName>SIZE</ogc:PropertyName></Size>' +
                                '</Graphic>' +
                            '</PointSymbolizer>' +
                        '</Rule>' +
                    '</FeatureTypeStyle>' +
                '</UserStyle>' +
            '</NamedLayer>' +
        '</StyledLayerDescriptor>';

    function test_read(t) {
        t.plan(23);

        var xml = new OpenLayers.Format.XML();
        var sldxml = xml.read(sld);

        // test that format options are considered in read
        var parser = new OpenLayers.Format.SLD({
            version: "1.0.0",
            namedLayersAsArray: true
        });
        var obj = parser.read(sldxml);
        t.ok(obj.namedLayers instanceof Array, "namedLayersAsArray option for read works");

        parser = new OpenLayers.Format.SLD.v1_0_0();
        var obj = parser.read(sldxml, {namedLayersAsArray: true});
        t.ok(obj.namedLayers instanceof Array, "namedLayersAsArray option for read works");
        var arrayLen = obj.namedLayers.length;

        var obj = parser.read(sldxml);
        t.eq(typeof obj.namedLayers, "object", "read returns a namedLayers object by default");
        // test the named layer count
        var count = 0;
        for(var key in obj.namedLayers) {
            ++count;
        }
        t.eq(count, arrayLen, "number of named layers in array equals number of named layers in object");

        var layer, style, rule;

        // check the first named layer
        layer = obj.namedLayers["AAA161"];
        t.ok(layer, "first named layer exists");
        t.ok(layer.userStyles instanceof Array, "(AAA161) layer has array of user styles");
        t.eq(layer.userStyles.length, 1, "(AAA161) first layer has a single user style");
        t.eq(layer.userStyles[0].rules.length, 2, "(AAA161) first style has two rules");
        var rule = layer.userStyles[0].rules[0];
        t.ok(rule.filter, "(AAA161) first rule has a filter");
        var symbolizer = rule.symbolizer;
        t.ok(symbolizer, "(AAA161) first rule has a symbolizer");
        var poly = symbolizer["Polygon"];
        t.eq(poly.fillColor, "#ffffff", "(AAA161) first rule has proper fill");
        t.eq(poly.strokeColor, "#000000", "(AAA161) first rule has proper stroke");
        var text = symbolizer["Text"];
        t.eq(text.label, "A ${FOO} label", "(AAA161) first rule has proper text label");
        t.eq(layer.userStyles[0].propertyStyles["label"], true, "label added to propertyStyles");
        t.eq(text.fontFamily, "Arial", "(AAA161) first rule has proper font family");
        t.eq(text.fontColor, "#000000", "(AAA161) first rule has proper text fill");
        t.eq(text.haloRadius, "3", "(AAA161) first rule has proper halo radius");
        t.eq(text.haloColor, "#ffffff", "(AAA161) first rule has proper halo color");


        // check the first user style
        style = layer.userStyles[0];
        t.ok(style instanceof OpenLayers.Style, "(AAA161,0) user style is instance of OpenLayers.Style");
        t.eq(style.rules.length, 2, "(AAA161,0) user style has 2 rules");

        // check the second rule
        rule = style.rules[1];
        var feature = {
            layer: {
                map: {
                    getScale: function(){
                        return 40000;
                    }
                }
            },
            attributes: {
                CTE: "900"
            }
        };
        t.ok(typeof rule.maxScaleDenominator == "number", "MaxScaleDenominator is a number");
        t.eq(rule.evaluate(feature), true, "numeric filter comparison evaluates correctly");

        // check for PropertyName size
        layer = obj.namedLayers["Second Layer"];
        style = layer.userStyles[0];
        rule = style.rules[0];
        t.eq(rule.symbolizer["Point"].graphicWidth, "${SIZE}", "dynamic size correctly set on graphicWidth");

        // etc.  I'm convinced read works, really wanted to test write (since examples don't test that)
        // I'll add more tests here later.

    }

    function test_write(t) {
        t.plan(3);

        // read first - testing that write produces the SLD above
        var parser = new OpenLayers.Format.SLD.v1_0_0();
        var xml = new OpenLayers.Format.XML();
        var sldxml = xml.read(sld);
        var obj = parser.read(sldxml);

        var node = parser.write(obj);
        t.xml_eq(node, sld, "SLD correctly written");

        obj = parser.read(sldxml, {namedLayersAsArray: true});
        node = parser.write(obj);
        t.xml_eq(node, sld, "SLD from namedLayers array correctly written");

        // test that 0 fill opacity gets written
        var symbolizer = {
            fillColor: "red",
            fillOpacity: 0
        };
        var root = parser.createElementNSPlus("PolygonSymbolizer");
        var got = parser.writeNode("Fill", symbolizer, root);
        var expect =
            '<Fill xmlns="http://www.opengis.net/sld">' +
                '<CssParameter name="fill">red</CssParameter>' +
                '<CssParameter name="fill-opacity">0</CssParameter>' +
            '</Fill>';
        t.xml_eq(got, expect, "zero fill opacity written");
    }

    function test_writePointSymbolizer(t) {

        t.plan(4);

        var parser = new OpenLayers.Format.SLD.v1_0_0();
        var symbolizer, node, exp;

        // test symbolizer with fill color only
        symbolizer = {
            "fillColor": "blue"
        };
        node = parser.writeNode("sld:PointSymbolizer", symbolizer);
        exp =
            '<PointSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Graphic>' +
                    '<Mark>' +
                        '<Fill>' +
                            '<CssParameter name="fill">blue</CssParameter>' +
                        '</Fill>' +
                        '<Stroke/>' +
                    '</Mark>' +
                '</Graphic>' +
            '</PointSymbolizer>';
        t.xml_eq(node, exp, "fillColor only written");

        // test symbolizer with stroke color only
        symbolizer = {
            "strokeColor": "blue"
        };
        node = parser.writeNode("sld:PointSymbolizer", symbolizer);
        exp =
            '<PointSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Graphic>' +
                    '<Mark>' +
                        '<Fill/>' +
                        '<Stroke>' +
                            '<CssParameter name="stroke">blue</CssParameter>' +
                        '</Stroke>' +
                    '</Mark>' +
                '</Graphic>' +
            '</PointSymbolizer>';
        t.xml_eq(node, exp, "strokeColor only written");

        // test symbolizer with graphic name only
        symbolizer = {
            "graphicName": "star"
        };
        node = parser.writeNode("sld:PointSymbolizer", symbolizer);
        exp =
            '<PointSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Graphic>' +
                    '<Mark>' +
                        '<WellKnownName>star</WellKnownName>' +
                        '<Fill/>' +
                        '<Stroke/>' +
                    '</Mark>' +
                '</Graphic>' +
            '</PointSymbolizer>';
        t.xml_eq(node, exp, "graphicName only written");

        // test symbolizer with geometry and some graphic
        symbolizer = {
            geometry: {
                property: "SOME_GEOM"
            },
            "graphicName": "star"
        };
        node = parser.writeNode("sld:PointSymbolizer", symbolizer);
        exp =
            '<PointSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Geometry>' +
                    '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">SOME_GEOM</ogc:PropertyName>' +
                '</Geometry>' +
                 '<Graphic>' +
                    '<Mark>' +
                        '<WellKnownName>star</WellKnownName>' +
                        '<Fill/>' +
                        '<Stroke/>' +
                    '</Mark>' +
                '</Graphic>' +
            '</PointSymbolizer>';
        t.xml_eq(node, exp, "geometry (with some graphic) written");
    }


    function test_writeLineSymbolizer(t) {

        t.plan(2);

        var parser = new OpenLayers.Format.SLD.v1_0_0();
        var symbolizer, node, exp;

        // test symbolizer with fill color only
        symbolizer = {
            strokeDashstyle: "4 4",
            strokeLinecap: "round",
            strokeColor: "#0000ff",
            strokeWidth: 2
        };
        node = parser.writeNode("sld:LineSymbolizer", symbolizer);
        exp =
            '<LineSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Stroke>' +
                    '<CssParameter name="stroke">#0000ff</CssParameter>' +
                    '<CssParameter name="stroke-width">2</CssParameter>' +
                    '<CssParameter name="stroke-dasharray">4 4</CssParameter>' +
                    '<CssParameter name="stroke-linecap">round</CssParameter>' +
                '</Stroke>' +
            '</LineSymbolizer>';
        t.xml_eq(node, exp, "line symbolizer correctly written");

        // test symbolizer with geometry and some stroke
        symbolizer = {
            geometry: {
                property: "SOME_GEOM"
            },
            strokeDashstyle: "4 4",
            strokeLinecap: "round",
            strokeColor: "#0000ff",
            strokeWidth: 2
        };
        node = parser.writeNode("sld:LineSymbolizer", symbolizer);
        exp =
            '<LineSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Geometry>' +
                    '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">SOME_GEOM</ogc:PropertyName>' +
                '</Geometry>' +
                '<Stroke>' +
                    '<CssParameter name="stroke">#0000ff</CssParameter>' +
                    '<CssParameter name="stroke-width">2</CssParameter>' +
                    '<CssParameter name="stroke-dasharray">4 4</CssParameter>' +
                    '<CssParameter name="stroke-linecap">round</CssParameter>' +
                '</Stroke>' +
            '</LineSymbolizer>';
        t.xml_eq(node, exp, "line symbolizer with geometry (and some stroke) written");

    }

    function test_writePolygonSymbolizer(t) {

        t.plan(1);
        var parser = new OpenLayers.Format.SLD.v1_0_0();
        // test symbolizer with geometry and some stroke
        var symbolizer = {
            Polygon: {
                geometry: {
                    property: "SOME_GEOM"
                }
            }
        };
        var node = parser.writers["sld"]["PolygonSymbolizer"].apply(
            parser, [symbolizer["Polygon"]]
        );

        var exp =
            '<PolygonSymbolizer xmlns="http://www.opengis.net/sld">' +
                 '<Geometry>' +
                     '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">SOME_GEOM</ogc:PropertyName>' +
                 '</Geometry>' +
                 '<Fill />' +
                 '<Stroke />' +
             '</PolygonSymbolizer>';
        t.xml_eq(node, exp, "polygon symbolizer with geometry written");
    }

    function test_writeTextSymbolizer(t) {
        t.plan(2);
        var parser = new OpenLayers.Format.SLD.v1_0_0();
        var symbolizer = {
            "Text": {
                "label": "This is the ${city} in ${state}.",
                "fontFamily": "Arial",
                "fontSize": 10,
                "fontColor": "blue",
                "fontWeight": "bold",
                "fontStyle": "normal",
                "haloRadius": 2,
                "haloColor": "white"
            }
        };
        var node = parser.writers["sld"]["TextSymbolizer"].apply(
            parser, [symbolizer["Text"]]
        );

        var expected =
            '<TextSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Label>' +
                    'This is the ' +
                    '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">city</ogc:PropertyName>' +
                    ' in ' +
                    '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">state</ogc:PropertyName>' +
                    '.' +
                '</Label>' +
                '<Font>' +
                    '<CssParameter name="font-family">Arial</CssParameter>' +
                    '<CssParameter name="font-size">10</CssParameter>' +
                    '<CssParameter name="font-weight">bold</CssParameter>' +
                    '<CssParameter name="font-style">normal</CssParameter>' +
                '</Font>' +
                '<Halo>' +
                    '<Radius>2</Radius>' +
                    '<Fill>' +
                        '<CssParameter name="fill">white</CssParameter>' +
                    '</Fill>' +
                '</Halo>' +
                '<Fill>' +
                    '<CssParameter name="fill">blue</CssParameter>' +
                '</Fill>' +
            '</TextSymbolizer>';

        t.xml_eq(node, expected, "Basic TextSymbolizer correctly written");

        // with geometry
        symbolizer = {
            "Text": {
                geometry: {
                    property: "SOME_GEOM"
                },
                "label": "This is the ${city} in ${state}.",
                "fontFamily": "Arial",
                "fontSize": 10,
                "fontColor": "blue",
                "fontWeight": "bold",
                "fontStyle": "normal",
                "haloRadius": 2,
                "haloColor": "white"
            }
        };
        node = parser.writers["sld"]["TextSymbolizer"].apply(
            parser, [symbolizer["Text"]]
        );

        expected =
            '<TextSymbolizer xmlns="http://www.opengis.net/sld">' +
                '<Geometry>' +
                    '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">SOME_GEOM</ogc:PropertyName>' +
                '</Geometry>' +
                '<Label>' +
                    'This is the ' +
                    '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">city</ogc:PropertyName>' +
                    ' in ' +
                    '<ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">state</ogc:PropertyName>' +
                    '.' +
                '</Label>' +
                '<Font>' +
                    '<CssParameter name="font-family">Arial</CssParameter>' +
                    '<CssParameter name="font-size">10</CssParameter>' +
                    '<CssParameter name="font-weight">bold</CssParameter>' +
                    '<CssParameter name="font-style">normal</CssParameter>' +
                '</Font>' +
                '<Halo>' +
                    '<Radius>2</Radius>' +
                    '<Fill>' +
                        '<CssParameter name="fill">white</CssParameter>' +
                    '</Fill>' +
                '</Halo>' +
                '<Fill>' +
                    '<CssParameter name="fill">blue</CssParameter>' +
                '</Fill>' +
            '</TextSymbolizer>';

        t.xml_eq(node, expected, "TextSymbolizer with geometry correctly written");

    }

    function test_writeSpatialFilter(t) {

        t.plan(1);

        var format = new OpenLayers.Format.SLD.v1_0_0();

        var rule = new OpenLayers.Rule({
            name: "test",
            filter: new OpenLayers.Filter.Spatial({
                type: OpenLayers.Filter.Spatial.BBOX,
                value: new OpenLayers.Bounds(0, 0, 10, 10)
            })
        });

        var sld = format.writeNode("sld:Rule", rule);

        var expect =
            '<Rule xmlns="http://www.opengis.net/sld">' +
                '<Name>test</Name>' +
                '<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">' +
                    '<ogc:BBOX>' +
                        '<gml:Box xmlns:gml="http://www.opengis.net/gml">' +
                            '<gml:coordinates decimal="." cs="," ts=" ">0,0 10,10</gml:coordinates>' +
                        '</gml:Box>' +
                    '</ogc:BBOX>' +
                '</ogc:Filter>' +
            '</Rule>';

        t.xml_eq(sld, expect, "rule with spatial filter correctly written");

    }

    function test_RasterSymbolizer(t) {
        t.plan(4);

        var format = new OpenLayers.Format.SLD.v1_0_0();

        var snippet =
            '<sld:RasterSymbolizer xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc">' +
                '<sld:Geometry>' +
                    '<ogc:PropertyName>geom</ogc:PropertyName>' +
                '</sld:Geometry>' +
                '<sld:Opacity>1</sld:Opacity>' +
                '<sld:ColorMap>' +
                    '<sld:ColorMapEntry color="#000000" opacity="0.5" quantity="0" label="nodata"/>' +
                    '<sld:ColorMapEntry color="#00FFFF" quantity="1" label="values"/>' +
                    '<sld:ColorMapEntry color="#FF0000" quantity="1000" label="values"/>' +
                '</sld:ColorMap>' +
            '</sld:RasterSymbolizer>';
        var expected = new OpenLayers.Format.XML().read(snippet).documentElement;

        var symbolizer = {};
        format.readNode(expected, {symbolizer: symbolizer});

        t.eq(symbolizer.Raster.colorMap[0].quantity, 0, "quantity set correctly");
        t.eq(symbolizer.Raster.colorMap[0].opacity, 0.5, "opacity set correctly");
        t.eq(symbolizer.Raster.colorMap[1].opacity, undefined, "non-existent opacity results in undefined");

        var got = format.writeNode("sld:RasterSymbolizer", symbolizer["Raster"]);

        t.xml_eq(got, expected, "Successfully round tripped RasterSymbolizer");
    }

    function test_zIndex(t) {
        t.plan(1);

        var format = new OpenLayers.Format.SLD.v1_0_0({
            multipleSymbolizers: true
        });

        // three zIndex values -> three FeatureTypeStyle elements
        var style = new OpenLayers.Style2({
            rules: [
                new OpenLayers.Rule({
                    filter: new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: "foo",
                        value: "bar"
                    }),
                    minScaleDenominator: 100000,
                    maxScaleDenominator: 200000,
                    symbolizers: [
                        new OpenLayers.Symbolizer.Line({
                            strokeColor: "green",
                            strokeWidth: 2,
                            zIndex: 2
                        }),
                        new OpenLayers.Symbolizer.Line({
                            strokeColor: "red",
                            strokeWidth: 3,
                            zIndex: -1
                        }),
                        new OpenLayers.Symbolizer.Line({
                            strokeColor: "blue",
                            strokeWidth: 1,
                            zIndex: 5
                        })
                    ]
                }),
                new OpenLayers.Rule({
                    filter: new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: "foo",
                        value: "baz"
                    }),
                    symbolizers: [
                        new OpenLayers.Symbolizer.Line({
                            strokeColor: "#000000",
                            strokeWidth: 2,
                            zIndex: 2
                        })
                    ]
                })
            ]
        });

        var got = format.writeNode("sld:UserStyle", style);
        var exp = readXML("zindex_test.sld").documentElement;
        t.xml_eq(got, exp, "duplicated rules to write zIndex as FeatureTypeStyle elements");

    }

    function test_whitespace(t) {
        t.plan(1);
        var xml = readXML("propertyisbetweenwhitespace.sld");
        var output = new OpenLayers.Format.SLD().read(xml);
        var filter = output.namedLayers['geonode:US_Stat0'].userStyles[0].rules[0].filter;
        t.eq(filter.lowerBoundary, 29.7, "whitespace ignored in values and value transformed to number");
    }

    function test_label_LinePlacement(t) {
        t.plan(1);
        var format = new OpenLayers.Format.SLD.v1_0_0({
            multipleSymbolizers: true
        });
        // labelPerpendicularOffset takes precedence over labelAlign
        var style = new OpenLayers.Style2({
            rules: [
                new OpenLayers.Rule({
                    symbolizers: [
                        new OpenLayers.Symbolizer.Line({
                            strokeColor: "red",
                            strokeWidth: 3
                        }),
                        new OpenLayers.Symbolizer.Text({
                            label: "${FOO}",
                            labelPerpendicularOffset: 10,
                            labelAlign: "rb"
                        })
                    ]
                })
            ]
        });
        var got = format.writeNode("sld:UserStyle", style);
        var exp = readXML("label_lineplacement_test.sld").documentElement;
        t.xml_eq(got, exp, "LinePlacement written out correctly");
    }

    function test_labelAlignToAnchorPosition(t) {
        t.plan(1);
        var format = new OpenLayers.Format.SLD.v1_0_0({
            multipleSymbolizers: true
        });
        var style = new OpenLayers.Style2({
            rules: [
                new OpenLayers.Rule({
                    symbolizers: [
                        new OpenLayers.Symbolizer.Text({
                            label: "${FOO}",
                            labelAlign: "rb"
                        })
                    ]
                })
            ]
        });
        var got = format.writeNode("sld:UserStyle", style);
        var exp = readXML("label_pointplacement_test.sld").documentElement;
        t.xml_eq(got, exp, "PointPlacement with labelAlign written out correctly");
    }

    function test_read_FeatureTypeStyles(t) {

        t.plan(13);

        var format = new OpenLayers.Format.SLD.v1_0_0({
            multipleSymbolizers: true,
            namedLayersAsArray: true
        });
        var doc = readXML("line_linewithborder.sld");

        var obj = format.read(doc);

        t.eq(obj.namedLayers.length, 1, "got one named layer");
        var namedLayer = obj.namedLayers[0];

        t.eq(namedLayer.userStyles.length, 1, "got one user style");
        var userStyle = namedLayer.userStyles[0];
        t.ok(userStyle instanceof OpenLayers.Style2, "user style represented with OpenLayers.Style2");

        // check rules and symbolizers
        var rule, symbolizer;

        t.eq(userStyle.rules.length, 2, "pulled two rules (from two FeatureTypeStyle elements)");
        rule = userStyle.rules[0];
        t.ok(rule instanceof OpenLayers.Rule, "first rule is an OpenLayers.Rule");

        t.eq(rule.symbolizers && rule.symbolizers.length, 1, "first rule has one symbolizer");
        symbolizer = rule.symbolizers[0];
        t.ok(symbolizer instanceof OpenLayers.Symbolizer, "first symbolizer in first rule is an OpenLayers.Symbolizer");
        t.ok(symbolizer instanceof OpenLayers.Symbolizer.Line, "first symbolizer in first rule is an OpenLayers.Symbolizer.Line");
        t.eq(symbolizer.zIndex, 0, "symbolizer from first FeatureTypeStyle element has zIndex 0");

        rule = userStyle.rules[1];
        t.eq(rule.symbolizers && rule.symbolizers.length, 1, "second rule has one symbolizer");
        symbolizer = rule.symbolizers[0];
        t.ok(symbolizer instanceof OpenLayers.Symbolizer, "first symbolizer in second rule is an OpenLayers.Symbolizer");
        t.ok(symbolizer instanceof OpenLayers.Symbolizer.Line, "first symbolizer in second rule is an OpenLayers.Symbolizer.Line");
        t.eq(symbolizer.zIndex, 1, "symbolizer from second FeatureTypeStyle element has zIndex 1");

    }

    function test_labelWhiteSpace(t) {
        t.plan(1);
        var doc = readXML("point_pointwithdefaultlabel.sld");
        var format = new OpenLayers.Format.SLD();
        var obj = format.read(doc);
        t.eq(obj.namedLayers["Point with default label"].userStyles[0].rules[0].symbolizer["Text"].label,
            "${name}", "Whitespace in front or after column name ignored");
    }

    function test_roundtrip(t) {

        t.plan(5);

        var format = new OpenLayers.Format.SLD.v1_0_0({
            multipleSymbolizers: true,
            namedLayersAsArray: true
        });
        var doc, out;

        // two FeatureTypeStyle elements and line symbolizers
        doc = readXML("line_linewithborder.sld");
        out = format.write(format.read(doc));
        t.xml_eq(out, doc.documentElement, "round-tripped line_linewithborder.sld");

        // three FeatureTypeStyle elements and line symbolizers
        doc = readXML("line_attributebasedline.sld");
        out = format.write(format.read(doc));
        t.xml_eq(out, doc.documentElement, "round-tripped line_attributebasedline.sld");

        // point symbolizer and text symbolizer
        doc = readXML("point_pointwithdefaultlabel.sld");
        out = format.write(format.read(doc));
        t.xml_eq(out, doc.documentElement, "round-tripped point_pointwithdefaultlabel.sld");

        // polygon symbolizer with fill only
        doc = readXML("polygon_simplepolygon.sld");
        out = format.write(format.read(doc));
        t.xml_eq(out, doc.documentElement, "round-tripped polygon_simplepolygon.sld");

        // polygon symbolizer and text symbolizer with halo
        doc = readXML("polygon_labelhalo.sld");
        out = format.write(format.read(doc));
        t.xml_eq(out, doc.documentElement, "round-tripped polygon_labelhalo.sld");
    }

    </script> 
</head> 
<body>
<div id="line_linewithborder.sld"><!--
<StyledLayerDescriptor version="1.0.0" 
    xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd" 
    xmlns="http://www.opengis.net/sld" 
    xmlns:ogc="http://www.opengis.net/ogc" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <NamedLayer>
    <Name>Line with border</Name>
    <UserStyle>
    <Title>SLD Cook Book: Line w2th border</Title>
      <FeatureTypeStyle>
         <Rule>
          <LineSymbolizer>
            <Stroke>
              <CssParameter name="stroke">#333333</CssParameter>                           
              <CssParameter name="stroke-width">5</CssParameter>    
              <CssParameter name="stroke-linecap">round</CssParameter>    
            </Stroke> 
          </LineSymbolizer>
        </Rule>
      </FeatureTypeStyle>
      <FeatureTypeStyle>
         <Rule>
          <LineSymbolizer>
          <Stroke>
              <CssParameter name="stroke">#6699FF</CssParameter>                           
              <CssParameter name="stroke-width">3</CssParameter> 
              <CssParameter name="stroke-linecap">round</CssParameter>  
            </Stroke>
          </LineSymbolizer>                                          
         </Rule>
      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>
--></div>
<div id="line_attributebasedline.sld"><!--
<StyledLayerDescriptor version="1.0.0" 
    xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd" 
    xmlns="http://www.opengis.net/sld" 
    xmlns:ogc="http://www.opengis.net/ogc" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <NamedLayer>
    <Name>Attribute-based line</Name>
    <UserStyle>
      <Title>SLD Cook Book: Attribute-based line</Title>
      <FeatureTypeStyle>
        <Rule>
          <Name>local-road</Name>
          <ogc:Filter>
            <ogc:PropertyIsEqualTo>
              <ogc:PropertyName>type</ogc:PropertyName>
              <ogc:Literal>local-road</ogc:Literal>
            </ogc:PropertyIsEqualTo>
          </ogc:Filter>
          <LineSymbolizer>
            <Stroke>
              <CssParameter name="stroke">#009933</CssParameter>
              <CssParameter name="stroke-width">2</CssParameter>
            </Stroke>
          </LineSymbolizer>
        </Rule>
      </FeatureTypeStyle>
      <FeatureTypeStyle>
        <Rule>
          <Name>secondary</Name>
          <ogc:Filter>
            <ogc:PropertyIsEqualTo>
              <ogc:PropertyName>type</ogc:PropertyName>
              <ogc:Literal>secondary</ogc:Literal>
            </ogc:PropertyIsEqualTo>
          </ogc:Filter>
          <LineSymbolizer>
            <Stroke>
              <CssParameter name="stroke">#0055CC</CssParameter>
              <CssParameter name="stroke-width">3</CssParameter>
            </Stroke>
          </LineSymbolizer>
        </Rule>
      </FeatureTypeStyle>
      <FeatureTypeStyle>
        <Rule>
        <Name>highway</Name>
          <ogc:Filter>
            <ogc:PropertyIsEqualTo>
              <ogc:PropertyName>type</ogc:PropertyName>
              <ogc:Literal>highway</ogc:Literal>
            </ogc:PropertyIsEqualTo>
          </ogc:Filter>
          <LineSymbolizer>
            <Stroke>
              <CssParameter name="stroke">#FF0000</CssParameter>
              <CssParameter name="stroke-width">6</CssParameter>
            </Stroke>
          </LineSymbolizer>
        </Rule>
      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor> 
--></div>
<div id="point_pointwithdefaultlabel.sld"><!--
<StyledLayerDescriptor version="1.0.0" 
    xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd" 
    xmlns="http://www.opengis.net/sld" 
    xmlns:ogc="http://www.opengis.net/ogc" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <NamedLayer>
    <Name>Point with default label</Name>
    <UserStyle>
      <Title>GeoServer SLD Cook Book: Point with default label</Title>
      <FeatureTypeStyle>
        <Rule>
          <PointSymbolizer>
            <Graphic>
              <Mark>
                <WellKnownName>circle</WellKnownName>
                <Fill>
                  <CssParameter name="fill">#FF0000</CssParameter>
                </Fill>
              </Mark>
              <Size>6</Size>
            </Graphic>
          </PointSymbolizer>
          <TextSymbolizer>
            <Label>
              <ogc:PropertyName>name</ogc:PropertyName>
            </Label>
            <Fill>
              <CssParameter name="fill">#000000</CssParameter>
            </Fill>
          </TextSymbolizer>
        </Rule>
      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>
--></div>
<div id="polygon_simplepolygon.sld"><!--
<StyledLayerDescriptor version="1.0.0" 
    xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd" 
    xmlns="http://www.opengis.net/sld" 
    xmlns:ogc="http://www.opengis.net/ogc" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <NamedLayer>
    <Name>Simple polygon</Name>
    <UserStyle>
      <Title>SLD Cook Book: Simple polygon</Title>
      <FeatureTypeStyle>
        <Rule>
          <PolygonSymbolizer>
            <Fill>
              <CssParameter name="fill">#000080</CssParameter>
            </Fill>
          </PolygonSymbolizer>
        </Rule>
      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>
--></div>
<div id="polygon_labelhalo.sld"><!--
<StyledLayerDescriptor version="1.0.0" 
    xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd" 
    xmlns="http://www.opengis.net/sld" 
    xmlns:ogc="http://www.opengis.net/ogc" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <NamedLayer>
    <Name>Label halo</Name>
    <UserStyle>
      <Title>SLD Cook Book: Label halo</Title>
      <FeatureTypeStyle>
        <Rule>
          <PolygonSymbolizer>
            <Fill>
              <CssParameter name="fill">#40FF40</CssParameter>
            </Fill>
            <Stroke>
              <CssParameter name="stroke">#FFFFFF</CssParameter>
              <CssParameter name="stroke-width">2</CssParameter>
            </Stroke>
          </PolygonSymbolizer>        
          <TextSymbolizer>
            <Label>
              <ogc:PropertyName>name</ogc:PropertyName>
            </Label>
            <Halo>
              <Radius>3</Radius>
              <Fill>
                <CssParameter name="fill">#FFFFFF</CssParameter>
              </Fill>
            </Halo>
          </TextSymbolizer>
        </Rule>
      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>
--></div>
<div id="zindex_test.sld"><!--
<sld:UserStyle xmlns:sld="http://www.opengis.net/sld">
    <sld:FeatureTypeStyle>
        <sld:Rule>
            <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
                <ogc:PropertyIsEqualTo>
                    <ogc:PropertyName>foo</ogc:PropertyName>
                    <ogc:Literal>bar</ogc:Literal>
                </ogc:PropertyIsEqualTo>
            </ogc:Filter>
            <sld:MinScaleDenominator>100000</sld:MinScaleDenominator>
            <sld:MaxScaleDenominator>200000</sld:MaxScaleDenominator>
            <sld:LineSymbolizer>
                <sld:Stroke>
                    <sld:CssParameter name="stroke">red</sld:CssParameter>
                    <sld:CssParameter name="stroke-width">3</sld:CssParameter>
                </sld:Stroke>
            </sld:LineSymbolizer>
        </sld:Rule>
    </sld:FeatureTypeStyle>
    <sld:FeatureTypeStyle>
        <sld:Rule>
            <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
                <ogc:PropertyIsEqualTo>
                    <ogc:PropertyName>foo</ogc:PropertyName>
                    <ogc:Literal>bar</ogc:Literal>
                </ogc:PropertyIsEqualTo>
            </ogc:Filter>
            <sld:MinScaleDenominator>100000</sld:MinScaleDenominator>
            <sld:MaxScaleDenominator>200000</sld:MaxScaleDenominator>
            <sld:LineSymbolizer>
                <sld:Stroke>
                    <sld:CssParameter name="stroke">green</sld:CssParameter>
                    <sld:CssParameter name="stroke-width">2</sld:CssParameter>
                </sld:Stroke>
            </sld:LineSymbolizer>
        </sld:Rule>
        <sld:Rule>
            <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
                <ogc:PropertyIsEqualTo>
                    <ogc:PropertyName>foo</ogc:PropertyName>
                    <ogc:Literal>baz</ogc:Literal>
                </ogc:PropertyIsEqualTo>
            </ogc:Filter>
            <sld:LineSymbolizer>
                <sld:Stroke>
                    <sld:CssParameter name="stroke">#000000</sld:CssParameter>
                    <sld:CssParameter name="stroke-width">2</sld:CssParameter>
                </sld:Stroke>
            </sld:LineSymbolizer>
        </sld:Rule>
    </sld:FeatureTypeStyle>
    <sld:FeatureTypeStyle>
        <sld:Rule>
            <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
                <ogc:PropertyIsEqualTo>
                    <ogc:PropertyName>foo</ogc:PropertyName>
                    <ogc:Literal>bar</ogc:Literal>
                </ogc:PropertyIsEqualTo>
            </ogc:Filter>
            <sld:MinScaleDenominator>100000</sld:MinScaleDenominator>
            <sld:MaxScaleDenominator>200000</sld:MaxScaleDenominator>
            <sld:LineSymbolizer>
                <sld:Stroke>
                    <sld:CssParameter name="stroke">blue</sld:CssParameter>
                    <sld:CssParameter name="stroke-width">1</sld:CssParameter>
                </sld:Stroke>
            </sld:LineSymbolizer>
        </sld:Rule>
    </sld:FeatureTypeStyle>
</sld:UserStyle>
--></div>
<div id="label_lineplacement_test.sld"><!--
<sld:UserStyle xmlns:sld="http://www.opengis.net/sld">
    <sld:FeatureTypeStyle>
        <sld:Rule>
            <sld:LineSymbolizer>
                <sld:Stroke>
                    <sld:CssParameter name="stroke">red</sld:CssParameter>
                    <sld:CssParameter name="stroke-width">3</sld:CssParameter>
                </sld:Stroke>
            </sld:LineSymbolizer>
            <sld:TextSymbolizer>
                <sld:Label><ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">FOO</ogc:PropertyName></sld:Label>
                <sld:LabelPlacement>
                    <sld:LinePlacement>
                        <sld:PerpendicularOffset>10</sld:PerpendicularOffset>
                    </sld:LinePlacement>
                </sld:LabelPlacement>
            </sld:TextSymbolizer>
        </sld:Rule>
    </sld:FeatureTypeStyle>
</sld:UserStyle>
--></div>
<div id="label_pointplacement_test.sld"><!--
<sld:UserStyle xmlns:sld="http://www.opengis.net/sld">
    <sld:FeatureTypeStyle>
        <sld:Rule>
            <sld:TextSymbolizer>
                <sld:Label><ogc:PropertyName xmlns:ogc="http://www.opengis.net/ogc">FOO</ogc:PropertyName></sld:Label>
                <sld:LabelPlacement>
                    <sld:PointPlacement>
                        <sld:AnchorPoint>
                            <sld:AnchorPointX>1</sld:AnchorPointX>
                            <sld:AnchorPointY>0</sld:AnchorPointY>
                        </sld:AnchorPoint>
                    </sld:PointPlacement>
                </sld:LabelPlacement>
            </sld:TextSymbolizer>
        </sld:Rule>
    </sld:FeatureTypeStyle>
</sld:UserStyle>
--></div>
<div id="propertyisbetweenwhitespace.sld"><!--
<sld:StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" version="1.0.0">
    <sld:NamedLayer>
        <sld:Name>geonode:US_Stat0</sld:Name>
        <sld:UserStyle>
            <sld:Name>US_Stat0_5cbbe918</sld:Name>
            <sld:Title>BMI&lt;25</sld:Title>
            <sld:FeatureTypeStyle>
                <sld:Name>name</sld:Name>
                <sld:Rule>
                    <sld:Title>BMI&lt;25</sld:Title>
                    <ogc:Filter>
                        <ogc:PropertyIsBetween>
                            <ogc:PropertyName>Hlt_st_BMI</ogc:PropertyName>
                            <ogc:LowerBoundary>
                                <ogc:Literal>


                                	29.7


                            </ogc:Literal>
                            </ogc:LowerBoundary>
                            <ogc:UpperBoundary>
                                <ogc:Literal>


                                 36.2


                            </ogc:Literal>
                            </ogc:UpperBoundary>
                        </ogc:PropertyIsBetween>
                    </ogc:Filter>
                    <sld:PolygonSymbolizer>
                        <sld:Fill>
                            <sld:CssParameter name="fill">#C0F58C</sld:CssParameter>
                        </sld:Fill>
                        <sld:Stroke/>
                    </sld:PolygonSymbolizer>
                </sld:Rule>
            </sld:FeatureTypeStyle>
        </sld:UserStyle>
    </sld:NamedLayer>
</sld:StyledLayerDescriptor>
--></div>
</body> 
</html> 
